package org.mybatis.generator.plugins;

import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.OutputUtilities;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.api.dom.xml.Document;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.codegen.mybatis3.ListUtilities;
import org.mybatis.generator.codegen.mybatis3.MyBatis3FormattingUtilities;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.utils.JavaMapperGeneratorHelper;
import org.mybatis.generator.utils.XMLMapperGeneratorHelper;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * <b><code>LombokPlugin</code></b>
 * <p/>
 * Description: 批量添加
 * <p/>
 * <b>Creation Time:</b> 2020/06/10.
 */
public class BatchInsertPlugin extends PluginAdapter {

	private final static String BATCH_INSERT = "batchInsert";

	private final static String PARAMETER_NAME = "recordList";

	@Override
	public boolean validate(List<String> list) {
		return true;
	}

	@Override
	public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass,
			IntrospectedTable introspectedTable) {
		if (introspectedTable.getTargetRuntime() == IntrospectedTable.TargetRuntime.MYBATIS3) {
			clientBatchInsertMethodGenerated(interfaze, introspectedTable, context);
		}
		return super.clientGenerated(interfaze, topLevelClass, introspectedTable);
	}

	@Override
	public boolean sqlMapDocumentGenerated(Document document, IntrospectedTable introspectedTable) {
		if (introspectedTable.getTargetRuntime() == IntrospectedTable.TargetRuntime.MYBATIS3) {
			sqlMapBatchInsertElementGenerated(document, introspectedTable);
		}
		return super.sqlMapDocumentGenerated(document, introspectedTable);
	}

	/**
	 * batchInsert SQL生成
	 *
	 * @param document
	 * @param introspectedTable
	 */
	private void sqlMapBatchInsertElementGenerated(Document document, IntrospectedTable introspectedTable) {

		List<IntrospectedColumn> columnList = ListUtilities
				.removeIdentityAndGeneratedAlwaysColumns(introspectedTable.getAllColumns());

		XmlElement baseElement = XMLMapperGeneratorHelper.baseElementGenerator(XMLMapperGeneratorHelper.INSERT,
				BATCH_INSERT, FullyQualifiedJavaType.getNewListInstance().getFullyQualifiedName(), null, null);

		XmlElement foreachElement = XMLMapperGeneratorHelper.baseForeachElementGenerator(PARAMETER_NAME, "item",
				"index", ",");

		StringBuilder insertClause = new StringBuilder();

		insertClause.append("insert into ");
		insertClause.append(introspectedTable.getFullyQualifiedTableNameAtRuntime());
		insertClause.append(" (");

		StringBuilder valuesClause = new StringBuilder();
		valuesClause.append(" (");
		List<String> valuesClauses = new ArrayList<String>();
		for (int i = 0; i < columnList.size(); i++) {
			IntrospectedColumn introspectedColumn = columnList.get(i);
			insertClause.append(MyBatis3FormattingUtilities.getEscapedColumnName(introspectedColumn));
			valuesClause.append(MyBatis3FormattingUtilities.getParameterClause(introspectedColumn, "item."));
			if (i != (columnList.size() - 1)) {
				insertClause.append(", ");
				valuesClause.append(", ");
			}
			if (valuesClause.length() > 80) {
				baseElement.addElement(new TextElement(insertClause.toString()));
				insertClause.setLength(0);
				OutputUtilities.xmlIndent(insertClause, 1);

				valuesClauses.add(valuesClause.toString());
				valuesClause.setLength(0);
				OutputUtilities.xmlIndent(valuesClause, 1);
			}
		}

		insertClause.append(')');
		baseElement.addElement(new TextElement(insertClause.toString()));

		valuesClause.append(')');
		valuesClauses.add(valuesClause.toString());

		baseElement.addElement(new TextElement("values"));

		for (String clause : valuesClauses) {
			foreachElement.addElement(new TextElement(clause));
		}

		baseElement.addElement(foreachElement);
		document.getRootElement().addElement(baseElement);
	}

	private void clientBatchInsertMethodGenerated(Interface interfaze, IntrospectedTable introspectedTable,
			Context context) {
		Set<FullyQualifiedJavaType> importedTypes = JavaMapperGeneratorHelper
				.importedBaseTypesGenerator(introspectedTable);

		FullyQualifiedJavaType listParameterType = FullyQualifiedJavaType.getNewListInstance();
		listParameterType.addTypeArgument(introspectedTable.getRules().calculateAllFieldsClass());

		Method batchInsertMethod = JavaMapperGeneratorHelper.methodGenerator(BATCH_INSERT, JavaVisibility.DEFAULT,
				FullyQualifiedJavaType.getIntInstance(),
				new Parameter(listParameterType, PARAMETER_NAME, "@Param(\"" + PARAMETER_NAME + "\")"));

		context.getCommentGenerator().addGeneralMethodComment(batchInsertMethod, introspectedTable);

		interfaze.addImportedTypes(importedTypes);
		interfaze.addMethod(batchInsertMethod);
	}

}